Python Object and Reference

Reason is the light and the light of life.

Jerry Su Apr 26, 2019 1 mins

C/C++中函数传递参数方式有:按值传递 和 按址传递。而在一切皆对象的Python中则完全不可延续C/C++的思想,而是要有可变对象不可变对象的概念才能理解。

变量与对象

Python中的变量与C/C++中变量的概念是不同的。

  • C/C++:

int a = 1 # 在栈上开辟地址为a的内存空间,存入值1

a = 2 # 修改变量a的值。

int b = a # 将变量a赋值给另一个变量变量b,本质是:拷贝a的值给b

  • Python

Python的变量本质是:内存对象的引用

a = 1 # 变量a指向了内存中的一个int型的对象。

a = 2 # 并非像C/C++中给变量a重新赋值,而是a将会移动并指向另一个对象2。当一个对象没有任何标签或引用指向它时,它就会被自动释放。

b = a # 把变量a赋给另一个变量b,只是给当前内存中对象增加一个引用而已。

Python一切皆对象

Python使用对象模型来储存数据,任何类型的值都是一个对象。所有的python对象都有3个特征:身份、类型、值。

  • 身份:每一个对象都有自己的唯一的标识,可以使用内建函数id()来得到它。这个值可以被认为是该对象的内存地址。

  • 类型:对象的类型决定了该对象可以保存的什么类型的值,可以进行什么操作,以及遵循什么样的规则。type()函数来查看对象的类型。

  • 值:对象表示的数据项。

a is b:通过id()判断是否为同一个对象的引用。

a == b:判断ab引用的对象的值是否相同。

可变对象和不可变对象

Python的基本数据类型中。

  • 可变对象: 列表, 字典

  • 不可变对象: 数字,字符串,元组

a = 1 # a指向内存中一个int型对象

a = 2 # 当将a重新赋值时,因为1是不可变对象,所以a会指向一个新的int型对象,其值为2

lst = [1, 2] # lst指向内存中一个list类型的对象

lst[0] = 2 # 重新赋值lst中第一个元素

因为list类型是可以改变的,所以第一个元素变更为2。更确切的说,lst的第一个元素是int型,重新赋值时一个新的int对象被指定给第一个元素,但是对于lst来说,它所指的列表型对象没有变,只是列表的内容(其中一个元素)改变了。

def foo(arg):
    arg = 5
    print(arg)

x = 1 # 不可变对象
foo(x)    # 5
print(x)  # 1
def foo(arg):
    arg.append(3)

x = [1, 2]  # 可变对象
print(x)   # [1, 2]
foo(x)
print(x)   # [1, 2, 3]

对于不可变的对象,类似传值方式;对于可变对象,类似按址传递。

深拷贝 浅拷贝

  1. 赋值:简单地拷贝对象的引用,两个对象的id相同。

  2. 浅拷贝:创建一个新的组合对象,这个新对象与原对象共享内存中的子对象。

  3. 深拷贝:创建一个新的组合对象,同时递归地拷贝所有子对象,新的组合对象与原对象没有任何关联。虽然实际上会共享不可变的子对象,但不影响它们的相互独立性。

浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其它对象的对象,如列表,类实例。而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。

深拷贝 浅拷贝


Read more:

Related posts: